package com.xxcxcxcx.xc_moremob.common.entities.monster.realization;

import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.network.syncher.SynchedEntityData;
import net.minecraft.sounds.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.util.Mth;
import net.minecraft.world.Difficulty;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.control.MoveControl;
import net.minecraft.world.entity.ai.goal.*;
import net.minecraft.world.entity.ai.goal.target.HurtByTargetGoal;
import net.minecraft.world.entity.ai.goal.target.NearestAttackableTargetGoal;
import net.minecraft.world.entity.ai.goal.target.TargetGoal;
import net.minecraft.world.entity.ai.navigation.GroundPathNavigation;
import net.minecraft.world.entity.ai.targeting.TargetingConditions;
import net.minecraft.world.entity.ai.util.GoalUtils;
import net.minecraft.world.entity.animal.IronGolem;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
import software.bernie.geckolib3.core.IAnimatable;
import software.bernie.geckolib3.core.PlayState;
import software.bernie.geckolib3.core.builder.AnimationBuilder;
import software.bernie.geckolib3.core.controller.AnimationController;
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
import software.bernie.geckolib3.core.manager.AnimationData;
import software.bernie.geckolib3.core.manager.AnimationFactory;

import javax.annotation.Nullable;
import java.util.EnumSet;
import java.util.function.Predicate;

public class FlyMeleeBasicEntity extends Monster implements IAnimatable{
    //定义一个动画事件处理器
    private AnimationFactory factory = new AnimationFactory(this);
    private boolean canBreakDoors;
    public boolean IsBabyFlyMelee;
    public boolean playAttackAnimation = false;
    public static final float FLAP_DEGREES_PER_TICK = 45.836624F;
    public static final int TICKS_PER_FLAP = Mth.ceil(3.9269907F);
    protected static final EntityDataAccessor<Byte> DATA_FLAGS_ID = SynchedEntityData.defineId(FlyMeleeBasicEntity.class, EntityDataSerializers.BYTE);
    private static final int FLAG_IS_CHARGING = 1;
    @Nullable
    Mob owner;
    @Nullable
    private BlockPos boundOrigin;
    private boolean hasLimitedLife;
    private int limitedLifeTicks;
    //枚举攻击状态
    public static final EntityDataAccessor<Integer> STATE = SynchedEntityData.defineId(FlyMeleeBasicEntity.class, EntityDataSerializers.INT);
    //打破大门的可能
    private final BreakDoorGoal breakDoorGoal = new BreakDoorGoal(this, DOOR_BREAKING_PREDICATE);
    private static final Predicate<Difficulty> DOOR_BREAKING_PREDICATE = (mode) -> {
        return mode == Difficulty.HARD || mode == Difficulty.NORMAL;
    };

    public FlyMeleeBasicEntity(EntityType<? extends Monster> type, Level worldIn) {
        super(type, worldIn);
        this.xpReward = 10;
        this.moveControl = new FlyMeleeBasicEntity.FlyMeleeMoveControl(this);
        this.setBaby(worldIn.getRandom().nextFloat()<0.05F);
    }
    public boolean isFlapping() {
        return this.tickCount % TICKS_PER_FLAP == 0;
    }
    public void move(MoverType p_33997_, Vec3 p_33998_) {
        super.move(p_33997_, p_33998_);
        this.checkInsideBlocks();
    }
    public void tick() {
        this.noPhysics = true;
        super.tick();
        this.noPhysics = false;
        this.setNoGravity(true);
        if (this.hasLimitedLife && --this.limitedLifeTicks <= 0) {
            this.limitedLifeTicks = 20;
            this.hurt(DamageSource.STARVE, 1.0F);
        }
    }
    protected void registerGoals() {
        this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F));
        this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
        this.addBehaviourGoals();
    }
    protected void addBehaviourGoals() {
        //将我们的攻击AI进行注册
        this.goalSelector.addGoal(0, new FloatGoal(this));
        this.goalSelector.addGoal(4, new FlyMeleeBasicEntity.FlyMeleeChargeAttackGoal());
        this.goalSelector.addGoal(8, new FlyMeleeBasicEntity.FlyMeleeRandomMoveGoal());
        this.goalSelector.addGoal(1, new FlyMeleeBasicEntity.FlyMeleeAttackGoal(this, 1.0D, false));
        this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, Raider.class)).setAlertOthers());
        this.targetSelector.addGoal(2, new FlyMeleeBasicEntity.FlyMeleeCopyOwnerTargetGoal(this));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Player.class, true));
        this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true));
    }
    public static AttributeSupplier.Builder prepareAttributes() {
        return Monster.createMonsterAttributes()
                .add(Attributes.MAX_HEALTH, 5D).
                add(Attributes.MOVEMENT_SPEED, (double)0.32F).
                add(Attributes.ATTACK_DAMAGE, 5.5D);
//        return Monster.createMonsterAttributes().
//                add(Attributes.FOLLOW_RANGE, 35.0D).
//                add(Attributes.MOVEMENT_SPEED, (double)0.23F).
//                add(Attributes.ATTACK_DAMAGE, 3.0D).
//                add(Attributes.ARMOR, 2.0D).
//                add(Attributes.SPAWN_REINFORCEMENTS_CHANCE);
    }
    public boolean isAlliedTo(Entity p_32665_) {
        if(p_32665_ == owner){
            return true;
        }
        return super.isAlliedTo(p_32665_);
    }
    //伤害函数
    public boolean doHurtTarget(Entity entityIn) {
        if(!super.doHurtTarget(entityIn))
        {
            this.playAttackAnimation=false;
            return false;
        }
        else{
            if(entityIn instanceof LivingEntity)
            {
                float f = this.level.getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty();
                ((LivingEntity)entityIn).addEffect(new MobEffectInstance(MobEffects.WITHER, 100 * (int)f,0,true,true));
            }
            return true;
        }

    }
    //该状态播放器控制生物平时的各种动作
    private <E extends IAnimatable> PlayState predicate(AnimationEvent<E> event) {
        //生物在移动，就播放移动的动画，路径和第2步的动作字符串对应
        if (event.isMoving()) {
            event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.model.move", true));
            return PlayState.CONTINUE;
        }
        //不动的话就播放闲置时的动画
        event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.model.base", true));
        return PlayState.CONTINUE;
    }

    //该状态播放器控制生物攻击时的各种动作
    private <E extends IAnimatable> PlayState predicate1(AnimationEvent<E> event) {
        //如果生物攻击状态为1并且没有死亡，就执行这个攻击动画
        if (this.entityData.get(STATE) == 1 && !(this.dead || this.getHealth() < 0.01 || this.isDeadOrDying())) {
            event.getController().setAnimation(new AnimationBuilder().addAnimation("animation.model.atk1", false));
            return PlayState.CONTINUE;
        }
        return PlayState.STOP;
    }
    //将我们之前的所有动画控制器进行注册
    @Override
    public void registerControllers(AnimationData data) {
        data.addAnimationController(new AnimationController(this, "controller",
                0, this::predicate));
        data.addAnimationController(new AnimationController(this, "controller1",
                0, this::predicate1));
    }

    @Override
    public AnimationFactory getFactory() {
        // TODO Auto-generated method stub
        return this.factory;
    }

    //生物实体声音
    @Nullable
    protected SoundEvent getAmbientSound() {
        return SoundEvents.VEX_AMBIENT;
    }

    protected SoundEvent getDeathSound() {
        return SoundEvents.VEX_DEATH;
    }

    protected SoundEvent getHurtSound(DamageSource p_34023_) {
        return SoundEvents.VEX_HURT;
    }

    protected void playStepSound(BlockPos pos, BlockState blockstate) {
        this.playSound(SoundEvents.ZOGLIN_STEP, 0.15F, 1.0F);
    }

    static class FlyMeleeBasicAttackGoal extends FlyMeleeAttackGoal {
        private final FlyMeleeBasicEntity zombie;
        public FlyMeleeBasicAttackGoal(FlyMeleeBasicEntity entity, double p_i46803_2_, boolean p_i46803_4_) {
            super(entity, p_i46803_2_, p_i46803_4_);
            this.zombie=entity;
        }
    }
    public boolean canBreakDoors() {
        return this.canBreakDoors;
    }
    protected boolean supportsBreakDoorGoal() {
        return true;
    }
    //怪物能不能破门而入
    public void setCanBreakDoors(boolean p_34337_) {
        if (this.supportsBreakDoorGoal() && GoalUtils.hasGroundPathNavigation(this)) {
            if (this.canBreakDoors != p_34337_) {
                this.canBreakDoors = p_34337_;
                ((GroundPathNavigation)this.getNavigation()).setCanOpenDoors(p_34337_);
                if (p_34337_) {
                    this.goalSelector.addGoal(1, this.breakDoorGoal);
                } else {
                    this.goalSelector.removeGoal(this.breakDoorGoal);
                }
            }
        } else if (this.canBreakDoors) {
            this.goalSelector.removeGoal(this.breakDoorGoal);
            this.canBreakDoors = false;
        }

    }

    public void addAdditionalSaveData(CompoundTag p_34015_) {
        super.addAdditionalSaveData(p_34015_);
        if (this.boundOrigin != null) {
            p_34015_.putInt("BoundX", this.boundOrigin.getX());
            p_34015_.putInt("BoundY", this.boundOrigin.getY());
            p_34015_.putInt("BoundZ", this.boundOrigin.getZ());
        }

        if (this.hasLimitedLife) {
            p_34015_.putInt("LifeTicks", this.limitedLifeTicks);
        }
        p_34015_.putBoolean("IsBaby", this.isBaby());
    }

    public void readAdditionalSaveData(CompoundTag p_34008_) {
        super.readAdditionalSaveData(p_34008_);
        if (p_34008_.contains("BoundX")) {
            this.boundOrigin = new BlockPos(p_34008_.getInt("BoundX"), p_34008_.getInt("BoundY"), p_34008_.getInt("BoundZ"));
        }

        if (p_34008_.contains("LifeTicks")) {
            this.setLimitedLife(p_34008_.getInt("LifeTicks"));
        }
        this.setBaby(p_34008_.getBoolean("IsBaby"));
    }
    public Mob getOwner() {
        return this.owner;
    }
    public BlockPos getBoundOrigin() {
        return this.boundOrigin;
    }
    public void setBoundOrigin(@Nullable BlockPos p_34034_) {
        this.boundOrigin = p_34034_;
    }
    private boolean getVexFlag(int p_34011_) {
        int i = this.entityData.get(DATA_FLAGS_ID);
        return (i & p_34011_) != 0;
    }
    private void setVexFlag(int p_33990_, boolean p_33991_) {
        int i = this.entityData.get(DATA_FLAGS_ID);
        if (p_33991_) {
            i |= p_33990_;
        } else {
            i &= ~p_33990_;
        }
        this.entityData.set(DATA_FLAGS_ID, (byte)(i & 255));
    }
    public boolean isCharging() {
        return this.getVexFlag(1);
    }
    public void setIsCharging(boolean p_34043_) {
        this.setVexFlag(1, p_34043_);
    }
    public void setOwner(Mob p_33995_) {
        this.owner = p_33995_;
    }
    public void setLimitedLife(int p_33988_) {
        this.hasLimitedLife = true;
        this.limitedLifeTicks = p_33988_;
    }
    public float getBrightness() {
        return 1.0F;
    }
    public boolean isBaby() {
        return IsBabyFlyMelee;
    }
    public void setBaby(boolean a){
        IsBabyFlyMelee=a;
    }
    public int getAttckingState() {
        return this.entityData.get(STATE);
    }
    public void setAttackingState(int time) {
        this.entityData.set(STATE, time);
    }

    @Override
    protected void defineSynchedData() {
        super.defineSynchedData();
        this.entityData.define(DATA_FLAGS_ID, (byte)0);
        this.entityData.define(STATE, 0);
    }
    //我们生物的AI，决定使用哪种攻击方式
    static class FlyMeleeAttackGoal extends MeleeAttackGoal {
        private final FlyMeleeBasicEntity parentEntity;
        //攻击计时器
        protected int raiseArmTicks = 0;

        public FlyMeleeAttackGoal(FlyMeleeBasicEntity p_26019_, double p_26020_, boolean p_26021_) {
            super(p_26019_, p_26020_, p_26021_);
            this.parentEntity = p_26019_;
        }
        public void start() {
            super.start();
            this.raiseArmTicks = 0;
        }

        public void stop() {
            super.stop();
            this.parentEntity.setAggressive(false);
        }
        public boolean canUse() {
            if(super.canUse()){
                return true;
            }
            this.parentEntity.setAttackingState(0);
            return false;
        }
        public void tick() {
            super.tick();
            ++this.raiseArmTicks;
            LivingEntity livingentity = this.mob.getTarget();
            if (this.raiseArmTicks >= 5 && this.getTicksUntilNextAttack() < this.getAttackInterval() / 2) {
                this.parentEntity.setAggressive(true);
                if (livingentity != null) {
                    if(livingentity.position().distanceTo(this.parentEntity.position())<3.5F)
                    this.parentEntity.setAttackingState(1);
                }else {
                    this.parentEntity.setAttackingState(0);
                }
            } else {
                this.parentEntity.setAggressive(false);
                this.parentEntity.setAttackingState(0);
            }
        }
    }
    class FlyMeleeChargeAttackGoal extends Goal {
        public FlyMeleeChargeAttackGoal() {
            this.setFlags(EnumSet.of(Goal.Flag.MOVE));
        }
        public boolean canUse() {
            if (FlyMeleeBasicEntity.this.getTarget() != null && !FlyMeleeBasicEntity.this.getMoveControl().hasWanted() && FlyMeleeBasicEntity.this.random.nextInt(reducedTickDelay(7)) == 0) {
                return FlyMeleeBasicEntity.this.distanceToSqr(FlyMeleeBasicEntity.this.getTarget()) > 4.0D;
            } else {
                return false;
            }
        }

        public boolean canContinueToUse() {
            return FlyMeleeBasicEntity.this.getMoveControl().hasWanted() && FlyMeleeBasicEntity.this.isCharging() && FlyMeleeBasicEntity.this.getTarget() != null && FlyMeleeBasicEntity.this.getTarget().isAlive();
        }

        public void start() {
            LivingEntity livingentity = FlyMeleeBasicEntity.this.getTarget();
            if (livingentity != null) {
                Vec3 vec3 = livingentity.getEyePosition();
                FlyMeleeBasicEntity.this.moveControl.setWantedPosition(vec3.x, vec3.y, vec3.z, 1.0D);
            }

            FlyMeleeBasicEntity.this.setIsCharging(true);
            FlyMeleeBasicEntity.this.playSound(SoundEvents.VEX_CHARGE, 1.0F, 1.0F);
        }

        public void stop() {
            FlyMeleeBasicEntity.this.setIsCharging(false);
        }

        public boolean requiresUpdateEveryTick() {
            return true;
        }

        public void tick() {
            LivingEntity livingentity = FlyMeleeBasicEntity.this.getTarget();
            if (livingentity != null) {
                if (FlyMeleeBasicEntity.this.getBoundingBox().intersects(livingentity.getBoundingBox())) {
                    FlyMeleeBasicEntity.this.doHurtTarget(livingentity);
                    FlyMeleeBasicEntity.this.setIsCharging(false);
                } else {
                    double d0 = FlyMeleeBasicEntity.this.distanceToSqr(livingentity);
                    if (d0 < 9.0D) {
                        Vec3 vec3 = livingentity.getEyePosition();
                        FlyMeleeBasicEntity.this.moveControl.setWantedPosition(vec3.x, vec3.y, vec3.z, 1.0D);
                    }
                }
            }
        }
    }
    class FlyMeleeCopyOwnerTargetGoal extends TargetGoal {
        private final TargetingConditions copyOwnerTargeting = TargetingConditions.forNonCombat().ignoreLineOfSight().ignoreInvisibilityTesting();

        public FlyMeleeCopyOwnerTargetGoal(PathfinderMob p_34056_) {
            super(p_34056_, false);
        }

        public boolean canUse() {
            return FlyMeleeBasicEntity.this.owner != null && FlyMeleeBasicEntity.this.owner.getTarget() != null && this.canAttack(FlyMeleeBasicEntity.this.owner.getTarget(), this.copyOwnerTargeting);
        }

        public void start() {
            FlyMeleeBasicEntity.this.setTarget(FlyMeleeBasicEntity.this.owner.getTarget());
            super.start();
        }
    }
    class FlyMeleeMoveControl extends MoveControl {
        public FlyMeleeMoveControl(FlyMeleeBasicEntity p_34062_) {
            super(p_34062_);
        }

        public void tick() {
            if (this.operation == MoveControl.Operation.MOVE_TO) {
                Vec3 vec3 = new Vec3(this.wantedX - FlyMeleeBasicEntity.this.getX(), this.wantedY - FlyMeleeBasicEntity.this.getY(), this.wantedZ - FlyMeleeBasicEntity.this.getZ());
                double d0 = vec3.length();
                if (d0 < FlyMeleeBasicEntity.this.getBoundingBox().getSize()) {
                    this.operation = MoveControl.Operation.WAIT;
                    FlyMeleeBasicEntity.this.setDeltaMovement(FlyMeleeBasicEntity.this.getDeltaMovement().scale(0.5D));
                } else {
                    FlyMeleeBasicEntity.this.setDeltaMovement(FlyMeleeBasicEntity.this.getDeltaMovement().add(vec3.scale(this.speedModifier * 0.05D / d0)));
                    if (FlyMeleeBasicEntity.this.getTarget() == null) {
                        Vec3 vec31 = FlyMeleeBasicEntity.this.getDeltaMovement();
                        FlyMeleeBasicEntity.this.setYRot(-((float)Mth.atan2(vec31.x, vec31.z)) * (180F / (float)Math.PI));
                        FlyMeleeBasicEntity.this.yBodyRot = FlyMeleeBasicEntity.this.getYRot();
                    } else {
                        double d2 = FlyMeleeBasicEntity.this.getTarget().getX() - FlyMeleeBasicEntity.this.getX();
                        double d1 = FlyMeleeBasicEntity.this.getTarget().getZ() - FlyMeleeBasicEntity.this.getZ();
                        FlyMeleeBasicEntity.this.setYRot(-((float)Mth.atan2(d2, d1)) * (180F / (float)Math.PI));
                        FlyMeleeBasicEntity.this.yBodyRot = FlyMeleeBasicEntity.this.getYRot();
                    }
                }
            }
        }
    }
    class FlyMeleeRandomMoveGoal extends Goal {
        public FlyMeleeRandomMoveGoal() {
            this.setFlags(EnumSet.of(Goal.Flag.MOVE));
        }
        public boolean canUse() {
            return !FlyMeleeBasicEntity.this.getMoveControl().hasWanted() && FlyMeleeBasicEntity.this.random.nextInt(reducedTickDelay(7)) == 0;
        }
        public boolean canContinueToUse() {
            return false;
        }
        public void tick() {
            BlockPos blockpos = FlyMeleeBasicEntity.this.getBoundOrigin();
            if (blockpos == null) {
                blockpos = FlyMeleeBasicEntity.this.blockPosition();
            }
            for(int i = 0; i < 3; ++i) {
                BlockPos blockpos1 = blockpos.offset(FlyMeleeBasicEntity.this.random.nextInt(15) - 7, FlyMeleeBasicEntity.this.random.nextInt(11) - 5, FlyMeleeBasicEntity.this.random.nextInt(15) - 7);
                if (FlyMeleeBasicEntity.this.level.isEmptyBlock(blockpos1)) {
                    FlyMeleeBasicEntity.this.moveControl.setWantedPosition((double)blockpos1.getX() + 0.5D, (double)blockpos1.getY() + 0.5D, (double)blockpos1.getZ() + 0.5D, 0.25D);
                    if (FlyMeleeBasicEntity.this.getTarget() == null) {
                        FlyMeleeBasicEntity.this.getLookControl().setLookAt((double)blockpos1.getX() + 0.5D, (double)blockpos1.getY() + 0.5D, (double)blockpos1.getZ() + 0.5D, 180.0F, 20.0F);
                    }
                    break;
                }
            }
        }
    }
}